import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;

public class GestionEnv {

	
	private static HashMap<String,Object> envGlobale = new HashMap<String,Object>();
	private static Bibliotheque biblio;
	
	public HashMap<String,Integer> argFctPredefinie = new HashMap<String,Integer>();
	
	public HashMap<String,Method> methodFctPredefinie = new HashMap<String,Method>();
	
	public GestionEnv(Bibliotheque biblio) {
		GestionEnv.biblio=biblio;
		
		argFctPredefinie.put("donnelocale", 2);
		argFctPredefinie.put("donne", 2);
		argFctPredefinie.put("chose", 1);
		argFctPredefinie.put("chose?", 1);
		argFctPredefinie.put("charger", 1);
		
		Class c = GestionEnv.class;
		Method[] tab = c.getMethods();
		
		Method  m;
		for (int i=0;i<tab.length;i++) {
			m = tab[i];
	
			if(m.getName().equals("donnelocale"))
				methodFctPredefinie.put("donnelocale", m);			
			if(m.getName().equals("donne"))
				methodFctPredefinie.put("donne", m);			
			if(m.getName().equals("chose"))
				methodFctPredefinie.put("chose", m);			
			if(m.getName().equals("chosep"))
				methodFctPredefinie.put("chose?", m);
			if(m.getName().equals("charger"))
				methodFctPredefinie.put("charger", m);
		}    
	};
	
	
	public static Object donnelocale(ArrayList<Object> v,  HashMap<String, Object> penv) throws ParseException, Exception{
		
		if((v.get(0) instanceof String) && v.size()==2) {
			if(chercherEtRemplaceValeur((String)v.get(0),v.get(1),penv) == false) {
				penv.put((String)v.get(0),v.get(1));
				return true;
			}
			else return false;
		}
		else return false;
	}
	
	public static boolean chercherEtRemplaceValeur(String cle, Object val,  HashMap<String, Object> penv) throws ParseException, Exception{
			
			if(penv.containsKey(cle)) {
				penv.put(cle,val);
				return true;
			}
			else
				if(penv.containsKey("env_sup")) {
				return chercherEtRemplaceValeur(cle,val,(HashMap)penv.get("env_sup"));
				}
				else
					return false;
	}
	
	
	public static Object donne(ArrayList<Object> v,  HashMap<String, Object> penv) throws ParseException, Exception{
		
		if((v.get(0) instanceof String) && v.size()==2) {
			envGlobale.put((String)v.get(0),v.get(1));
			return true;
		}
		else return false;
	}
	
	public static Object chose(ArrayList<Object> v,  HashMap<String, Object> penv) throws ParseException, Exception{
		
		if((v.get(0) instanceof String) && v.size()==1) 
			if (envGlobale.containsKey((String)v.get(0)))
				return envGlobale.get((String)v.get(0));
			else
				if (penv.containsKey((String)v.get(0)))
					return penv.get((String)v.get(0));
				else
					if(penv.containsKey("env_sup"))
						return chose(v,(HashMap)penv.get("env_sup"));
					else 
						throw new Error("la variable "+(String)v.get(0)+" n'est dans l'env");
		else
			throw new Error("la variable "+(String)v.get(0)+" n'est dans l'env");
		}
	
	
	public static Object chosep(ArrayList<Object> v,  HashMap<String, Object> penv){
		
		if(v.get(0) instanceof String && v.size() == 1)
			return penv.containsKey((String)v.get(0)) || envGlobale.containsKey((String)v.get(0));
		else	
			return null;
	}
	
public static Object charger(ArrayList<Object> v,  HashMap<String, Object> penv){

		String ligne = "";
		try{
			InputStream ips=new FileInputStream((String) v.get(0)); 
			InputStreamReader ipsr=new InputStreamReader(ips);
			BufferedReader br=new BufferedReader(ipsr);			
			while ((ligne+=br.readLine())!=null)
			{
				ligne+="\n";
			}
			br.close(); 
		}		
		catch (Exception e){
			System.out.println(e.toString());
		}
		
		ArrayList<Object> instruction = new ArrayList<Object>();
    	ByteArrayInputStream stream  = new ByteArrayInputStream(ligne.getBytes());	    	
    	Trans parser = new Trans(stream);
    	parser.initBibliotheque(biblio);
    	Evaluation E = new Evaluation();
    	E.initEnv(new HashMap<String, Object>());
    	
    		try {
				instruction = parser.run();
			} catch (ParseException e1) {
				e1.printStackTrace();
			} catch (Exception e1) {
				e1.printStackTrace();
			}
    		System.out.println("instruction : " + instruction);
        	try {
				E.evalListe(instruction);
			} catch (IllegalArgumentException e1) {
				e1.printStackTrace();
			} catch (IllegalAccessException e1) {
				e1.printStackTrace();
			} catch (InvocationTargetException e1) {
				e1.printStackTrace();
			}		
		return null;
	}
	
	
}
